package com.piper.controller;

import com.piper.config.UrlProperties;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

@Controller
public class DispatchController {

    @Autowired
    private CloseableHttpClient httpClient;

    /**
     * 入口控制器
     *
     * @author wangzhongqiang
     * @data 2018/7/3 10:57
     */
    @RequestMapping({"/**"})
    public void dispatch(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        //获取路由地址
        String uri = uriRoute(httpServletRequest);

        CloseableHttpResponse response = null;
        try {
            // 判断前台的请求方式 对应创建不同类型请求 因为post和get传值方式不同
            String reqMethod = httpServletRequest.getMethod();
            if ("POST".equals(reqMethod)) {
                response = httpClient.execute(postMethod(uri, httpServletRequest));
            } else {
                response = httpClient.execute(getMethod(uri, httpServletRequest));
            }

            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND){
                httpServletResponse.sendError(response.getStatusLine().getStatusCode());
            }else {
                // html类型数据需要在里面的css和js链接前面加入标记，其他的数据直接返回前台
                if (response.getFirstHeader("Content-Type").getValue().contains("text/html")) {
                    htmlHandle(httpServletResponse, response, serverName(httpServletRequest));
                } else {
                    fileHandle(httpServletResponse, response);
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != response) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 返回post方法
     *
     * @author wangzhongqiang
     * @data 2018/7/3 11:19
     */
    HttpPost postMethod(String uri, HttpServletRequest httpServletRequest){
        StringEntity entity = null;

        if(httpServletRequest.getContentType().contains("json")){
            entity = jsonData(httpServletRequest);
        }else {
            entity = formData(httpServletRequest);
        }

        HttpPost httpPost = new HttpPost(uri);
        httpPost.setHeader("Content-Type", httpServletRequest.getHeader("Content-Type"));
        httpPost.setEntity(entity);
        return httpPost;
    }

    /**
     * 处理post请求form数据
     *
     * @author wangzhongqiang
     * @data 2018/7/17 18:05
     */
    public UrlEncodedFormEntity formData(HttpServletRequest httpServletRequest){
        UrlEncodedFormEntity urlEncodedFormEntity = null;
        try {
            // 获取前台表单数据
            List<NameValuePair> pairs = new ArrayList<>();
            Enumeration<String> params = httpServletRequest.getParameterNames();
            while (params.hasMoreElements()){
                String name = params.nextElement();
                pairs.add(new BasicNameValuePair(name, httpServletRequest.getParameter(name)));
            }
            urlEncodedFormEntity = new UrlEncodedFormEntity(pairs, httpServletRequest.getCharacterEncoding());
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
        return urlEncodedFormEntity;
    }

    /**
     * 处理post请求json数据
     *
     * @author wangzhongqiang
     * @data 2018/7/17 18:05
     */
    public StringEntity jsonData(HttpServletRequest httpServletRequest) {
        InputStreamReader is = null;
        StringEntity se = null;
        try {
            is =new InputStreamReader(httpServletRequest.getInputStream(), httpServletRequest.getCharacterEncoding());
            BufferedReader reader = new BufferedReader(is);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            se = new StringEntity(sb.toString(), httpServletRequest.getCharacterEncoding());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return se;
    }

    /**
     * 返回get方法
     *
     * @author wangzhongqiang
     * @data 2018/7/3 11:19
     */
    HttpGet getMethod(String uri, HttpServletRequest httpServletRequest){
        try {
            URIBuilder builder = new URIBuilder(uri);
            Enumeration<String> enumeration = httpServletRequest.getParameterNames();
            //将前台的参数放到我的请求里
            while (enumeration.hasMoreElements()) {
                String nex = enumeration.nextElement();
                builder.setParameter(nex, httpServletRequest.getParameter(nex));
            }
            return new HttpGet(builder.build());
        }catch (URISyntaxException e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 处理html
     *
     * @author wangzhongqiang
     * @data 2018/7/3 10:56
     */
    public void htmlHandle(HttpServletResponse httpServletResponse, CloseableHttpResponse response, String path) {
        try {
            setHeader(httpServletResponse, response);

            String html = EntityUtils.toString(response.getEntity());
            String res = htmlConvert(html, path);

            PrintWriter writer = httpServletResponse.getWriter();
            writer.print(res);
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理文件
     *
     * @author wangzhongqiang
     * @data 2018/7/3 10:56
     */
    public void fileHandle(HttpServletResponse httpServletResponse, CloseableHttpResponse response) {
        ServletOutputStream out = null;
        try {
            setHeader(httpServletResponse, response);

            HttpEntity entity = response.getEntity();
            out = httpServletResponse.getOutputStream();
            entity.writeTo(out);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置返回头信息
     *
     * @author piper
     * @date 2018/7/23 9:46
     */
    public void setHeader(HttpServletResponse httpServletResponse, CloseableHttpResponse response){
        Header encode = response.getFirstHeader("Content-Type");
        httpServletResponse.setHeader(encode.getName(), encode.getValue());

        //下载文件，文件名在这里
        Header desposition = response.getFirstHeader("Content-Desposition");
        if(null != desposition){
            httpServletResponse.setHeader(desposition.getName(), desposition.getValue());
        }

    }

    /**
     * 转换html页面里的链接
     *
     * @author wangzhongqiang
     * @data 2018/7/3 10:55
     */
    String htmlConvert(String html, String path) {

        //path形如： kafka,eureka之类，是yml文件里map属性下的服务名
        path = "/" + path;
        String path2 = path + "/";

        Document doc = Jsoup.parse(html);

        // 找到所有包含src属性，但是链接不以http开头的元素
        Elements src = doc.select("[src~=^(?!http).*$]");
        Elements href = doc.select("[href~=^(?!(http|#)).*$]");
        Elements action = doc.select("[action]");

        for (Element e : src) {
            String link = e.attr("src");
            if (link.startsWith("/")) {
                e.attr("src", path + link);
            } else {
                e.attr("src", path2 + link);
            }
        }
        for (Element e : href) {
            String link = e.attr("href");
            if (link.startsWith("/")) {
                e.attr("href", path + link);
            } else {
                e.attr("href", path2 + link);
            }
        }
        for (Element e : action) {
            String link = e.attr("action");
            if (link.startsWith("/")) {
                e.attr("action", path + link);
            } else {
                e.attr("action", path2 + link);
            }
        }
        return doc.outerHtml();
    }

    /**
     * 获取路由服务
     * @param httpServletRequest
     * @return
     */
    String uriRoute(HttpServletRequest httpServletRequest){
        //将请求转到对应的服务上
        // 比如将localhost:8080/eureka 转到 172.30.10.73:8762
        // localhost:8080/eureka/min.js 转到 172.30.10.73:8762/min.js
        Map<String, String> urlMap = UrlProperties.map;
        String path = serverName(httpServletRequest);
        if (urlMap.containsKey(path)) {
            return urlMap.get(path) + httpServletRequest.getRequestURI().substring(path.length() + 1);
        } else {
            return null;
        }
    }

    /**
     * 获取服务名称
     *
     * @author wangzhongqiang
     * @data 2018/7/3 10:54
     */
    String serverName(HttpServletRequest httpServletRequest){
        String uri = httpServletRequest.getRequestURI();
        String path = "";
        try {
            int lastIndex = uri.indexOf("/", 1);
            if (lastIndex == -1) {
                path = uri.substring(1);
            } else {
                path = uri.substring(1, uri.indexOf("/", 1));
            }
        } catch (StringIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
        return path;
    }

}
